package com.koron.sinoprobe.web.ledger.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.koron.bean.workflow.RedirectQuery;
import com.koron.common.core.business.workflow.templates.WorkFlowHandler;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import com.koron.sinoprobe.config.Constants;
import com.koron.sinoprobe.web.common.CommonUtils;
import com.koron.sinoprobe.web.ledger.bean.convertor.PlanConvertor;
import com.koron.sinoprobe.web.ledger.bean.entity.SpProject;
import com.koron.sinoprobe.web.ledger.bean.entity.SpProjectChange;
import com.koron.sinoprobe.web.ledger.bean.query.SpProjectChangeQuery;
import com.koron.sinoprobe.web.ledger.bean.vo.SpProjectChangeVO;
import com.koron.sinoprobe.web.ledger.bean.vo.SpProjectVO;
import com.koron.sinoprobe.web.ledger.mapper.SpProjectChangeMapper;
import com.koron.sinoprobe.web.ledger.mapper.SpProjectMapper;
import com.koron.sinoprobe.web.ledger.service.SpProjectChangeService;
import com.koron.sinoprobe.web.ledger.service.SpProjectService;
import com.koron.sinoprobe.web.plan.bean.entity.SpAssistDept;
import com.koron.sinoprobe.web.plan.bean.entity.SpMember;
import com.koron.sinoprobe.web.plan.bean.entity.SpPlanMilestone;
import com.koron.sinoprobe.web.plan.mapper.SpPlanMilestoneMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.List;

/**
 * @author twcao
 * @title: SpProjectChangeServiceImpl
 * @projectName GDH_EAM_V2
 * @description: 项目变更service
 * @date 2022/2/1116:37
 */
@Slf4j
@Service
public class SpProjectChangeServiceImpl implements SpProjectChangeService {

    @Autowired
    private SpProjectService projectService;

    @Autowired
    private PlanConvertor planConvertor;

    @Autowired
    private WorkFlowHandler workFlowHandler;

    @Override
    @TaskAnnotation("queryById")
    public SpProjectChangeVO queryById(SessionFactory factory, String id) {
        SpProjectChangeMapper mapper = factory.getMapper(SpProjectChangeMapper.class);
        return mapper.queryById(id);
    }

    @Override
    @TaskAnnotation("getDetailById")
    public SpProjectChangeVO getDetailById(SessionFactory factory, String id) {
        SpProjectChangeVO vo = queryById(factory, id);
        SpProjectMapper projectMapper = factory.getMapper(SpProjectMapper.class);
        if(StringUtils.equals(Constants.ChangeType.MEMORABILIA_CHANGE, vo.getChangeType())) {
            if(StringUtils.equals(Constants.ChangeMemorabiliaStatus.APPROVED, vo.getStatus())) { // 合并之后，前后位置调换
                //1、 里程碑变更（后）
                SpProjectVO afterChange = projectMapper.queryDetailById(vo.getProjectId());
                vo.setAfterChange(afterChange);
                //2、里程碑变更（前）
                SpProjectVO beforeChange = new SpProjectVO();
                BeanUtils.copyProperties(afterChange, beforeChange);
                SpPlanMilestoneMapper milestoneMapper = factory.getMapper(SpPlanMilestoneMapper.class);
                List<SpPlanMilestone> spPlanMilestones = planConvertor.milestonesVOTOBeans(milestoneMapper.getBySpId(id));
                beforeChange.setMilestone(spPlanMilestones);
                vo.setBeforeChange(beforeChange);
            } else {
                //1、里程碑变更（前）
                SpProjectVO beforeChange = projectMapper.queryDetailById(vo.getProjectId());
                vo.setBeforeChange(beforeChange);
                //2、 里程碑变更（后）
                SpProjectVO afterChange = new SpProjectVO();
                BeanUtils.copyProperties(beforeChange, afterChange);
                SpPlanMilestoneMapper milestoneMapper = factory.getMapper(SpPlanMilestoneMapper.class);
                List<SpPlanMilestone> spPlanMilestones = planConvertor.milestonesVOTOBeans(milestoneMapper.getBySpId(id));
                afterChange.setMilestone(spPlanMilestones);
                vo.setAfterChange(afterChange);
            }
        } else {
            if(StringUtils.equals(Constants.ChangeInfoStatus.CHANGED, vo.getStatus())) { // 合并之后，前后位置调换
                //1、项目信息变更（前）
                SpProjectVO beforeChange = projectMapper.queryDetailById(id);
                vo.setBeforeChange(beforeChange);
                //2、项目信息变更（后）
                SpProjectVO afterChange = projectMapper.queryDetailById(vo.getProjectId());
                vo.setAfterChange(afterChange);
            } else {
                //1、项目信息变更（前）
                SpProjectVO beforeChange = projectMapper.queryDetailById(vo.getProjectId());
                vo.setBeforeChange(beforeChange);
                //2、项目信息变更（后）
                SpProjectVO afterChange = projectMapper.queryDetailById(id);
                vo.setAfterChange(afterChange);
            }
        }
        return vo;
    }

    @Override
    @TaskAnnotation("queryList")
    public List<SpProjectChange> queryList(SessionFactory factory, SpProjectChangeQuery query) {
        SpProjectChangeMapper mapper = factory.getMapper(SpProjectChangeMapper.class);
        return mapper.queryList(query);
    }

    @Override
    @TaskAnnotation("saveOrUpdateVo")
    public SpProjectChangeVO saveOrUpdateVo(SessionFactory factory, SpProjectChangeVO bean) {
        Assert.notNull(bean, "项目变更不能为空");
        Assert.hasText(bean.getProjectId(), "项目id不能为空");
        //1、保存基础信息
        saveOrUpdate(factory, bean);
        // 2、获取变更后的内容（需要保存的内容）
        SpProjectVO afterChange = bean.getAfterChange();
        SpPlanMilestoneMapper milestoneMapper = factory.getMapper(SpPlanMilestoneMapper.class);
        // 2.1、新增里程碑（若是里程碑变更,里程碑列表不为空）
        List<SpPlanMilestone> milestones = afterChange.getMilestone();
        // 先删除里程碑，以后提交的为主
        milestoneMapper.deleteBySpId(bean.getId());
        if (!CollectionUtils.isEmpty(milestones)) {
            CommonUtils.sorted(milestones);
            milestones.stream().forEach(row -> {
                row.setSpId(bean.getId());
                row.setId(CodeTools.getCode32());
            });
            milestoneMapper.addBatch(milestones);
        }
        // 3、新增或修改变更后内容（含协助部门和成员）
        afterChange.setId(StringUtils.isEmpty(afterChange.getId()) ? CodeTools.getCode32() : afterChange.getId());
        afterChange.setPlanId(bean.getId());
        afterChange.setDeleteFlag(true);
        projectService.saveOrUpdate(factory, afterChange);
        return bean;
    }

    @Override
    @TaskAnnotation("saveOrUpdate")
    public SpProjectChangeVO saveOrUpdate(SessionFactory factory, SpProjectChangeVO bean, Boolean submit) {
        SpProjectChangeMapper mapper = factory.getMapper(SpProjectChangeMapper.class);
        // 当前操作是否是提交
        boolean isSubmit = false;
        if(submit != null) {
            isSubmit = submit;
        } else {
            if (StringUtils.isNotBlank(bean.getId())) {
                SpProjectChangeVO db = mapper.queryById(bean.getId());
                // 保存的状态和数据库的状态不一致，视为提交
                isSubmit = db == null || !StringUtils.equals(db.getStatus(), bean.getStatus());
            } else {
                isSubmit = StringUtils.equals(Constants.ChangeType.PROJECT_CHANGE, bean.getChangeType()) && StringUtils.equals(Constants.ChangeInfoStatus.CHANGED, bean.getStatus());
            }
        }
        // 保存
        saveOrUpdateVo(factory, bean);
        if(StringUtils.equals(Constants.ChangeType.PROJECT_CHANGE, bean.getChangeType()) && StringUtils.equals(Constants.ChangeInfoStatus.CHANGED, bean.getStatus()) && isSubmit) {
            // 项目基础信息变更（里程碑变更，由工作流走完后调用change方法）
            bean.setStatus(Constants.ChangeInfoStatus.DRAFT);
            saveOrUpdate(factory, bean);
            submit(factory, bean.getId());
        }
        return bean;
    }

    /**
     * 只保存基础信息
     * @param factory
     * @param change
     * @return
     */
    @Override
    public SpProjectChange saveOrUpdate(SessionFactory factory, SpProjectChange change) {
        SpProjectChangeMapper mapper = factory.getMapper(SpProjectChangeMapper.class);
        // 保存
        CommonUtils.update(change, ThreadLocalContext.get());
        change.setId(StringUtils.isEmpty(change.getId()) ? CodeTools.getCode32() : change.getId());
        if(StringUtils.isBlank(change.getStatus())) {
            change.setStatus(StringUtils.equals(change.getChangeType(), Constants.ChangeType.PROJECT_CHANGE) ? Constants.ChangeInfoStatus.DRAFT : Constants.ChangeMemorabiliaStatus.DRAFT);
        }
        if(StringUtils.isBlank(change.getCode())) {
            SpProjectMapper projectMapper = factory.getMapper(SpProjectMapper.class);
            SpProject spProject = projectMapper.queryById(change.getProjectId());
            String codeNo = CodeTools.getCurrAppCodeNoWithNoDate(spProject.getCode() + "_" + Constants.SP_PROJECT_BG_CODE, "", 3);
            change.setCode(codeNo);
        }
        // 1、保存项目变更的基础信息
        mapper.saveOrUpdate(change);
        return change;
    }

    /**
     * 删除一条项目变更记录，含里程碑列表
     * @param factory
     * @param id
     * @return
     */
    @Override
    @TaskAnnotation("deleteById")
    public Boolean deleteById(SessionFactory factory, String id) {
        return deleteById(factory, id, true);
    }

    @Override
    @TaskAnnotation("deleteById")
    public Boolean deleteById(SessionFactory factory, String id, boolean isDeleteWorkflow) {
        SpProjectChangeMapper mapper = factory.getMapper(SpProjectChangeMapper.class);
        mapper.deleteById(id);
        projectService.deleteByPlanId(factory, id);
        SpPlanMilestoneMapper milestoneMapper = factory.getMapper(SpPlanMilestoneMapper.class);
        milestoneMapper.deleteBySpId(id);
        // 删除工作流
        if (isDeleteWorkflow) {
            workFlowHandler.delete(id);
        }
        return true;
    }

    @Override
    @TaskAnnotation("workflowUpdate")
    public Boolean workflowUpdate(SessionFactory factory, RedirectQuery redirectQuery) {
        Integer operation = redirectQuery.getOperation();
        SpProjectChangeVO bean = JSON.parseObject(redirectQuery.getFormVariables(), SpProjectChangeVO.class);
        switch (operation) {
            case 256: // 撤回
            case 1: // 驳回
                // 驳回的节点编号
                bean.setStatus(Constants.ChangeMemorabiliaStatus.DRAFT);
                saveOrUpdate(factory, bean);
                break;
            case 32: // 同意
                bean.setStatus(Constants.ChangeMemorabiliaStatus.WAIT_REVIEW);
                saveOrUpdate(factory, bean);
                break;
        }
        return true;
    }

    @Override
    @TaskAnnotation("auditFinish")
    public SpProjectChange auditFinish(SessionFactory factory, SpProjectChangeVO bean) {
        // 里程碑变更审核完成
        bean.setStatus(Constants.ChangeMemorabiliaStatus.APPROVED);
        // 变更完成后，自动将变更的内容同步到项目中
        submit(factory, bean.getId());
        return saveOrUpdate(factory, bean);
    }

    /**
     * 项目变更（出发条件：1、完成信息变更流程，2、完成里程碑变更流程）
     *
     * @param factory 会话
     * @param id      项目变更id
     * @return 是否变更成功
     */
    @Override
    public boolean submit(SessionFactory factory, String id) {
        SpProjectChangeVO detail = getDetailById(factory, id);
        SpProjectVO afterChange = detail.getAfterChange();
        SpProjectVO beforeChange = detail.getBeforeChange();
        log.info("合并前：beforeChange = {}, afterChange = {}", JSON.toJSONString(beforeChange), JSON.toJSONString(afterChange));
        // 缓存变更前的项目
        SpProjectVO bak = new SpProjectVO();
        BeanUtils.copyProperties(beforeChange, bak);
        switch (detail.getChangeType()) {
            case Constants.ChangeType.PROJECT_CHANGE:
                // 如果基本信息有变更，将原先的值设置为需要变成的值
                beforeChange.setName(afterChange.getName());
                beforeChange.setBizCategory(afterChange.getBizCategory());
                beforeChange.setProjectType(afterChange.getProjectType());
                beforeChange.setMajor(afterChange.getMajor());
                beforeChange.setImportantLevel(afterChange.getImportantLevel());
                beforeChange.setHostDeptId(afterChange.getHostDeptId());
                beforeChange.setHostDeptName(afterChange.getHostDeptName());
                beforeChange.setHostOrgId(afterChange.getHostOrgId());
                beforeChange.setHostOrgName(afterChange.getHostOrgName());
                beforeChange.setNecessity(afterChange.getNecessity());
                beforeChange.setFeasibility(afterChange.getFeasibility());
                // 协助部门
                List<SpAssistDept> assistDept = afterChange.getAssistDept();
                // 项目id不变
                String changeId = beforeChange.getId();
                assistDept.forEach(row -> row.setSpId(changeId));
                beforeChange.setAssistDept(assistDept);
                beforeChange.setPredictFinishTime(afterChange.getPredictFinishTime());
                beforeChange.setAcceptCriteria(afterChange.getAcceptCriteria());
                beforeChange.setContentOverview(afterChange.getContentOverview());
                beforeChange.setIsTeam(afterChange.getIsTeam());
                beforeChange.setLeader(afterChange.getLeader());
                beforeChange.setLeaderName(afterChange.getLeaderName());
                // 成员
                List<SpMember> member = afterChange.getMember();
                member.forEach(row -> row.setSpId(changeId));
                beforeChange.setMember(member);
                beforeChange.setIsExpected(afterChange.getIsExpected());
                beforeChange.setBudget(afterChange.getBudget());
                beforeChange.setRemark(afterChange.getRemark());
                // 更新信息
                beforeChange.setUpdateBy(afterChange.getUpdateBy());
                beforeChange.setUpdateByName(afterChange.getUpdateByName());
                beforeChange.setUpdateTime(new Date());
                detail.setStatus(Constants.ChangeInfoStatus.CHANGED);
                break;
            case Constants.ChangeType.MEMORABILIA_CHANGE:
                // 里程碑变更
                beforeChange.setMilestone(afterChange.getMilestone());
                detail.setStatus(Constants.ChangeMemorabiliaStatus.APPROVED);
                break;
        }
        // 完成项目变更
        log.info("合并后：beforeChange = {}, afterChange = {}", JSON.toJSONString(beforeChange), JSON.toJSONString(afterChange));
        projectService.saveOrUpdate(factory, beforeChange);
        // 删掉变更后的值
        deleteById(factory, id, false);
        // 将变更前的值，存在到变更后的值里
        bak.setId(id);
        detail.setAfterChange(bak);
        // 设置完成时间
        detail.setFinishTime(new Date());
        saveOrUpdateVo(factory, detail);
        return true;
    }
}
